﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;

namespace Mancala.Net
{
    public partial class MancalaForm : Form
    {
        private const string PLAYER1_COINS_WON = "Player 1 Coins Won: ";
        private const string PLAYER2_COINS_WON = "Player 2 Coins Won: ";

        private const int START_POSITION = 0;
        private const int END_POSITION = 11;

        private Board m_mancalaBoard = new Board();        
        private List<Button> m_positionsCache = new List<Button>();

        public MancalaForm()
        {
            InitializeComponent();
        }

        private void MancalaForm_Load(object sender, EventArgs e)
        {
            PopulatePositionsCache();
            InitializeBoard();                    
        }

        private void PopulatePositionsCache()
        {
            m_positionsCache.Add(m_button1);
            m_positionsCache.Add(m_button2);
            m_positionsCache.Add(m_button3);
            m_positionsCache.Add(m_button4);
            m_positionsCache.Add(m_button5);
            m_positionsCache.Add(m_button6);
            m_positionsCache.Add(m_button7);
            m_positionsCache.Add(m_button8);
            m_positionsCache.Add(m_button9);
            m_positionsCache.Add(m_button10);
            m_positionsCache.Add(m_button11);
            m_positionsCache.Add(m_button12);
        }

        private void InitializeBoard()
        {
            List<int> coins = new List<int>();
            for (int i = START_POSITION; i <= END_POSITION; i++)
            {
                coins.Add(5);
            }
            PopulateBoard(coins);

            m_player1CoinsWon.Text = PLAYER1_COINS_WON + "0";
            m_player2CoinsWon.Text = PLAYER2_COINS_WON + "0";

            DisablePlayer2();
        }

        private void PopulateBoard(List<int> coins)
        {
            foreach (Button button in m_positionsCache)
            {
                SetCoinCount(button, coins[GetPosition(button)]);
            }
        }

        public void SetCoinCount(Button button, int coinCount)
        {
            if (coinCount != -1)
                button.Text = coinCount.ToString();
        }

        private void Button_Click(object sender, EventArgs e)
        {
            PerformMove(sender as Button);
        }

        private void PerformMove(Button button)
        {
            int position = GetPosition(button);
            int coinCount = GetCoinCount(button);
            int positionThatWon;

            button.Text = "0";

            if (position == END_POSITION)
                positionThatWon = PerformMove(START_POSITION, coinCount);
            else
                positionThatWon = PerformMove(position + 1, coinCount);
            
            AfterMoveComplete(position, positionThatWon);            
        }

        private int PerformMove(int position, int coinCount)
        {
            int newCoinCount;
            int positionThatWon = -1;
            for (int i = position; i <= END_POSITION; i++)
            {
                if (coinCount > 0)
                {
                    Button buttonToAddCoinsTo = GetButtonAtPosition(i);
                    newCoinCount = GetCoinCount(buttonToAddCoinsTo) + 1;
                    SetCoinCount(buttonToAddCoinsTo, newCoinCount);
                    coinCount -= 1;

                    if (newCoinCount == 1)
                        positionThatWon = i;
                    else
                        positionThatWon = -1;
                }
            }

            if(coinCount > 0)
                positionThatWon = PerformMove(START_POSITION, coinCount);
            return positionThatWon;
        }

        private void AfterMoveComplete(int position, int positionThatWon)
        {
            int coinsWon = 0;
            if (positionThatWon != -1)
            {
                int positionToWinCoinsFrom = m_mancalaBoard.GetOppositePositionIndex(positionThatWon);
                coinsWon = GetCoinCount(GetButtonAtPosition(positionToWinCoinsFrom));
                SetCoinCount(GetButtonAtPosition(positionToWinCoinsFrom), 0);
            }

            if (position < 6)
            {
                DisablePlayer1();
                m_player1CoinsWon.Text = PLAYER1_COINS_WON + (GetCoinsWonCount(m_player1CoinsWon) + coinsWon);
                TryPlayer1SideCleared();
            }
            else
            {
                DisablePlayer2();
                m_player2CoinsWon.Text = PLAYER2_COINS_WON + (GetCoinsWonCount(m_player2CoinsWon) + coinsWon);
                TryPlayer2SideCleared();
            }

            DisableButtonsWithNoCoins();
            TryGameComplete();
        }

        private void TryPlayer1SideCleared()
        {
            if (IsSideCleared(0))
            {
                m_player1CoinsWon.Text = PLAYER1_COINS_WON + (GetCoinsWonCount(m_player1CoinsWon) + 
                    GetCoinCountFromSide(6));
            }
        }

        private void TryPlayer2SideCleared()
        {
            if (IsSideCleared(6))
            {
                m_player2CoinsWon.Text = PLAYER2_COINS_WON + (GetCoinsWonCount(m_player2CoinsWon) +
                    GetCoinCountFromSide(0));
            }
        }

        private bool IsSideCleared(int startPosition)
        {
            for (int i = startPosition; i <= startPosition + 5; i++)
            {
                if(GetCoinCount(GetButtonAtPosition(i)) != 0) return false;
            }
            return true;
        }

        private int GetCoinCountFromSide(int startPosition)
        {
            int coinCount = 0;
            for (int i = startPosition; i <= startPosition + 5; i++)
            {
                coinCount += GetCoinCount(GetButtonAtPosition(i));
                SetCoinCount(GetButtonAtPosition(i), 0);
            }
            return coinCount;
        }

        private void TryGameComplete()
        {
            for (int i = START_POSITION; i <= END_POSITION; i++)
            {
                if (GetButtonAtPosition(i).Enabled)
                    return;
            }

            this.Text += " - Game Complete!";
        }

        private int GetPosition(Button button)
        {
            return Board.GetNumber(button.Name) - 1;
        }

        private int GetCoinCount(Button button)
        {
            return Board.GetNumber(button.Text);
        }

        private int GetCoinsWonCount(TextBox textBox)
        {
            return Board.GetNumber(textBox.Text);
        }

        private Button GetButtonAtPosition(int position)
        {
            position += 1;

            foreach (Button button in m_positionsCache)
            {
                int comparePosition;
                try
                {
                    comparePosition = int.Parse(button.Name.Substring(button.Name.Length - 2));
                }
                catch
                {
                    comparePosition = int.Parse(button.Name.Substring(button.Name.Length - 1));
                }

                if (comparePosition == position)
                    return button;
            }

            System.Diagnostics.Debug.Assert(false, 
                string.Format("No button found for provided position '{0}'", position.ToString()));
            return null;
        }

        private void DisablePlayer1()
        {
            ToggleButtonState(START_POSITION, 5, false);
            ToggleButtonState(6, END_POSITION, true);
        }
        
        private void DisablePlayer2()
        {
            ToggleButtonState(START_POSITION, 5, true);
            ToggleButtonState(6, END_POSITION, false);
        }

        private void DisableButtonsWithNoCoins()
        {
            for (int i = START_POSITION; i <= END_POSITION; i++)
            {
                Button button = GetButtonAtPosition(i);
                if (GetCoinCount(button) == 0)
                    button.Enabled = false;
            }
        }

        private void ToggleButtonState(int startPosition, int endPosition, bool isEnabled)
        {
            for (int i = startPosition; i <= endPosition; i++)
            {
                ToggleButtonState(i, isEnabled);
            }
        }

        private void ToggleButtonState(int position, bool isEnabled)
        {
            GetButtonAtPosition(position).Enabled = isEnabled;
        }
    }
}
